﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using YArchitech.ProgressBar;
using YJKGeometryFuncs;
using YJKRevitStructModel.Data;

namespace YJKRevitStructModel.Kit
{
	public class DeductionWall
	{
		public DeductionWall(Autodesk.Revit.DB.Document doc, Dictionary<ElementDataPack, List<ElementDataPack>> dicDeductionWall)
		{
			this.m_doc = doc;
			this.InitDeductionInformationByCurrentDocWall(dicDeductionWall);
		}

		public bool Run()
		{
			if (this.m_dicDeductionWall.Count == 0)
			{
				return true;
			}
			ProgressBarForm progressBarForm = new ProgressBarForm(this.m_dicDeductionWall.Count, ProgressBarStyle.Blocks, true);
			progressBarForm.Text = "墙体扣减进度显示";
			progressBarForm.ShowInTaskbar = false;
			progressBarForm.Show(CmdStructuralModelDeduction._hWndRevit);
			try
			{
				foreach (KeyValuePair<ElementId, List<ElementDataPack>> keyValuePair in this.m_dicDeductionWall)
				{
					if (progressBarForm.m_stopTag)
					{
						return false;
					}
					progressBarForm.RefreshProgressBar();
					if (keyValuePair.Value.Count != 0)
					{
						List<ElementId> list = new List<ElementId>();
						list.Add(keyValuePair.Key);
						foreach (ElementDataPack elementDataPack in keyValuePair.Value)
						{
							(elementDataPack as WallDataPack).GetWallCrv();
							Curve locatinCrv = (elementDataPack as WallDataPack).LocatinCrv;
							Wall wall = null;
							if (list.Count == 1)
							{
								wall = (this.m_doc.GetElement(list[0]) as Wall);
							}
							else
							{
								if (list.Count <= 1)
								{
									break;
								}
								double val = double.MaxValue;
								foreach (ElementId elementId in list)
								{
									Wall wall2 = this.m_doc.GetElement(elementId) as Wall;
									double num = (wall2.Location as LocationCurve).Curve.Distance(locatinCrv.Evaluate(0.5, true));
									if (Geometry.LessThan(num, val))
									{
										val = num;
										wall = wall2;
									}
								}
							}
							this.DeductionSingleWall(ref list, wall, locatinCrv);
							this.m_doc.Regenerate();
						}
						if (list.Count == 0 && keyValuePair.Value.Count == 1)
						{
							this.NumEqual++;
						}
					}
				}
			}
			catch (Exception)
			{
				progressBarForm.Dispose();
				return false;
			}
			return true;
		}

		private void DeductionSingleWall(ref List<ElementId> lstWallId, Wall wall, Curve LinkWallCrv)
		{
			if (!this.DisallowJoinWall(wall.Id))
			{
				return;
			}
			Curve curve = (wall.Location as LocationCurve).Curve;
			if (this.isCurvesCoincide(curve, ref LinkWallCrv))
			{
				int num = lstWallId.FindIndex((ElementId e) => e == wall.Id);
				if (num != -1)
				{
					lstWallId.RemoveAt(num);
				}
				this.m_doc.Delete(wall.Id);
				return;
			}
			if (Geometry.GreaterThan(curve.Length, LinkWallCrv.Length))
			{
				List<Curve> newWallLocationCrv = this.GetNewWallLocationCrv(curve, LinkWallCrv);
				if (newWallLocationCrv.Count == 2)
				{
					XYZ xyz = new XYZ(2000.0, 0.0, 0.0);
					List<ElementId> list = ElementTransformUtils.CopyElement(this.m_doc, wall.Id, xyz) as List<ElementId>;
					Wall wall2 = this.m_doc.GetElement(list[0]) as Wall;
					ElementTransformUtils.MoveElement(this.m_doc, wall2.Id, -xyz);
					(wall2.Location as LocationCurve).Curve = newWallLocationCrv[0];
					lstWallId.Add(wall2.Id);
					xyz = new XYZ(1000.0, 0.0, 0.0);
					list = (ElementTransformUtils.CopyElement(this.m_doc, wall.Id, xyz) as List<ElementId>);
					Wall wall3 = this.m_doc.GetElement(list[0]) as Wall;
					ElementTransformUtils.MoveElement(this.m_doc, wall3.Id, -xyz);
					(wall3.Location as LocationCurve).Curve = newWallLocationCrv[1];
					lstWallId.Add(wall3.Id);
				}
				else if (newWallLocationCrv.Count == 1)
				{
					XYZ xyz2 = new XYZ(2000.0, 0.0, 0.0);
					List<ElementId> list2 = ElementTransformUtils.CopyElement(this.m_doc, wall.Id, xyz2) as List<ElementId>;
					Wall wall4 = this.m_doc.GetElement(list2[0]) as Wall;
					ElementTransformUtils.MoveElement(this.m_doc, wall4.Id, -xyz2);
					(wall4.Location as LocationCurve).Curve = newWallLocationCrv[0];
					lstWallId.Add(wall4.Id);
				}
			}
			int num2 = lstWallId.FindIndex((ElementId e) => e == wall.Id);
			if (num2 != -1)
			{
				lstWallId.RemoveAt(num2);
			}
			this.m_doc.Delete(wall.Id);
		}

		private void GetNewStructWallCrv(Curve crvBase, ref Curve crvLink)
		{
			XYZ endPoint = crvLink.GetEndPoint(0);
			XYZ endPoint2 = crvLink.GetEndPoint(1);
			Curve curve = crvBase.Clone();
			curve.MakeUnbound();
			Curve curve2 = crvLink.Clone();
			curve2.MakeUnbound();
			double parameter = curve.Project(endPoint).Parameter;
			double parameter2 = curve.Project(endPoint2).Parameter;
			if (crvBase.IsInside(parameter))
			{
				if (crvBase.IsInside(parameter2))
				{
					return;
				}
				parameter = curve2.Project(crvBase.GetEndPoint(0)).Parameter;
				if (crvLink.IsInside(parameter))
				{
					if (Geometry.LessThan(endPoint.DistanceTo(crvBase.GetEndPoint(0)), 0.0001))
					{
						return;
					}
					if (crvLink.IsCyclic)
					{
						XYZ xyz = crvLink.Evaluate(parameter / 2.0, false);
						Arc.Create(endPoint, crvBase.GetEndPoint(0), xyz);
						return;
					}
					crvLink = Line.CreateBound(endPoint, crvBase.GetEndPoint(0));
					return;
				}
				else
				{
					if (Geometry.LessThan(endPoint.DistanceTo(crvBase.GetEndPoint(1)), 0.0001))
					{
						return;
					}
					if (crvLink.IsCyclic)
					{
						parameter = curve2.Project(crvBase.GetEndPoint(1)).Parameter;
						XYZ xyz2 = crvLink.Evaluate(parameter / 2.0, false);
						Arc.Create(endPoint, crvBase.GetEndPoint(1), xyz2);
						return;
					}
					crvLink = Line.CreateBound(endPoint, crvBase.GetEndPoint(1));
					return;
				}
			}
			else
			{
				if (!crvBase.IsInside(parameter2))
				{
					crvLink = crvBase.Clone();
					return;
				}
				parameter = curve2.Project(crvBase.GetEndPoint(0)).Parameter;
				if (crvLink.IsInside(parameter))
				{
					if (Geometry.LessThan(crvBase.GetEndPoint(0).DistanceTo(endPoint2), 0.0001))
					{
						return;
					}
					if (crvLink.IsCyclic)
					{
						XYZ xyz3 = crvLink.Evaluate(parameter / 2.0, false);
						crvLink = Arc.Create(crvBase.GetEndPoint(0), endPoint2, xyz3);
						return;
					}
					crvLink = Line.CreateBound(crvBase.GetEndPoint(0), endPoint2);
					return;
				}
				else
				{
					if (Geometry.LessThan(crvBase.GetEndPoint(1).DistanceTo(endPoint2), 0.0001))
					{
						return;
					}
					if (crvLink.IsCyclic)
					{
						parameter = curve2.Project(crvBase.GetEndPoint(1)).Parameter;
						XYZ xyz4 = crvLink.Evaluate(parameter / 2.0, false);
						crvLink = Arc.Create(crvBase.GetEndPoint(1), endPoint2, xyz4);
						return;
					}
					crvLink = Line.CreateBound(crvBase.GetEndPoint(1), endPoint2);
					return;
				}
			}
		}

		private List<Curve> GetNewWallLocationCrv(Curve crvWall, Curve crvCut)
		{
			double val = 0.03;
			List<Curve> list = new List<Curve>();
			XYZ endPoint = crvWall.GetEndPoint(0);
			double val2 = endPoint.DistanceTo(crvCut.GetEndPoint(0));
			double val3 = endPoint.DistanceTo(crvCut.GetEndPoint(1));
			if (crvWall is Arc)
			{
				Arc arc = crvWall as Arc;
				Arc arc2 = crvCut as Arc;
				XYZ xyz = (arc.GetEndPoint(0) - arc.Center).Normalize();
				XYZ xyz2 = (arc.GetEndPoint(1) - arc.Center).Normalize();
				XYZ xyz3 = (arc2.GetEndPoint(0) - arc2.Center).Normalize();
				XYZ xyz4 = (arc2.GetEndPoint(1) - arc2.Center).Normalize();
				double num = xyz.AngleOnPlaneTo(arc.XDirection, arc.Normal);
				double num2 = xyz2.AngleOnPlaneTo(arc.XDirection, arc.Normal);
				double num3 = xyz3.AngleOnPlaneTo(arc.XDirection, arc.Normal);
				double num4 = xyz4.AngleOnPlaneTo(arc.XDirection, arc.Normal);
				Arc item;
				Arc item2;
				if (Geometry.LessThan(val2, val3))
				{
					item = Arc.Create(arc.Center, arc.Radius, num, num3, arc.XDirection, arc.YDirection);
					item2 = Arc.Create(arc.Center, arc.Radius, num4, num2, arc.XDirection, arc.YDirection);
				}
				else
				{
					item = Arc.Create(arc.Center, arc.Radius, num, num4, arc.XDirection, arc.YDirection);
					item2 = Arc.Create(arc.Center, arc.Radius, num3, num2, arc.XDirection, arc.YDirection);
				}
				list.Add(item);
				list.Add(item2);
			}
			else
			{
				this.CorrectLinkLineByBaseLine(crvWall, ref crvCut);
				SetComparisonResult setComparisonResult = crvWall.Intersect(crvCut);
				if (setComparisonResult != SetComparisonResult.Overlap && setComparisonResult != SetComparisonResult.Subset && setComparisonResult != SetComparisonResult.Superset && setComparisonResult != SetComparisonResult.Equal)
				{
					list.Add(crvWall);
					return list;
				}
				if (Geometry.LessThan(val2, val3))
				{
					if (Geometry.GreaterThan(endPoint.DistanceTo(crvCut.GetEndPoint(0)), val))
					{
						list.Add(Line.CreateBound(endPoint, crvCut.GetEndPoint(0)));
					}
					if (Geometry.GreaterThan(crvCut.GetEndPoint(1).DistanceTo(crvWall.GetEndPoint(1)), val))
					{
						list.Add(Line.CreateBound(crvCut.GetEndPoint(1), crvWall.GetEndPoint(1)));
					}
				}
				else
				{
					if (Geometry.GreaterThan(endPoint.DistanceTo(crvCut.GetEndPoint(1)), val))
					{
						list.Add(Line.CreateBound(endPoint, crvCut.GetEndPoint(1)));
					}
					if (Geometry.GreaterThan(crvCut.GetEndPoint(0).DistanceTo(crvWall.GetEndPoint(1)), val))
					{
						list.Add(Line.CreateBound(crvCut.GetEndPoint(0), crvWall.GetEndPoint(1)));
					}
				}
			}
			return list;
		}

		private void CorrectLinkLineByBaseLine(Curve crvBase, ref Curve crvLink)
		{
			double val = 0.01;
			XYZ endPoint = crvBase.GetEndPoint(0);
			XYZ endPoint2 = crvBase.GetEndPoint(1);
			Line line = crvBase.Clone() as Line;
			line.MakeUnbound();
			XYZ xyzpoint = line.Project(crvLink.GetEndPoint(0)).XYZPoint;
			XYZ xyzpoint2 = line.Project(crvLink.GetEndPoint(1)).XYZPoint;
			bool flag = crvBase.IsInside(line.Project(crvLink.GetEndPoint(0)).Parameter);
			bool flag2 = crvBase.IsInside(line.Project(crvLink.GetEndPoint(1)).Parameter);
			if (!flag && flag2)
			{
				double val2 = endPoint.DistanceTo(xyzpoint);
				double num = endPoint2.DistanceTo(xyzpoint2);
				if (Geometry.GreaterThan(val2, num))
				{
					if (Geometry.GreaterThan(num, val))
					{
						crvLink = Line.CreateBound(endPoint2, xyzpoint2);
						return;
					}
				}
				else
				{
					num = endPoint.DistanceTo(xyzpoint2);
					if (Geometry.GreaterThan(num, val))
					{
						crvLink = Line.CreateBound(endPoint, xyzpoint2);
						return;
					}
				}
			}
			else if (!flag2 && flag)
			{
				double val3 = endPoint.DistanceTo(xyzpoint2);
				double val4 = endPoint2.DistanceTo(xyzpoint2);
				if (Geometry.GreaterThan(val3, val4))
				{
					crvLink = Line.CreateBound(endPoint2, xyzpoint);
					return;
				}
				crvLink = Line.CreateBound(endPoint, xyzpoint);
				return;
			}
			else
			{
				crvLink = Line.CreateBound(xyzpoint, xyzpoint2);
			}
		}

		private bool isCurvesCoincide(Curve crv1, ref Curve crv2)
		{
			List<XYZ> list = new List<XYZ>();
			List<XYZ> list2 = new List<XYZ>();
			list.Add(crv1.GetEndPoint(0));
			list.Add(crv1.Evaluate(0.5, true));
			list.Add(crv1.GetEndPoint(1));
			Curve curve = crv1.Clone();
			curve.MakeUnbound();
			XYZ xyzpoint = curve.Project(crv2.GetEndPoint(0)).XYZPoint;
			XYZ xyzpoint2 = curve.Project(crv2.Evaluate(0.5, true)).XYZPoint;
			XYZ xyzpoint3 = curve.Project(crv2.GetEndPoint(1)).XYZPoint;
			list2.Add(xyzpoint);
			list2.Add(xyzpoint2);
			list2.Add(xyzpoint3);
			if (crv2 is Arc)
			{
				crv2 = Arc.Create(xyzpoint, xyzpoint3, xyzpoint2);
			}
			else
			{
				crv2 = Line.CreateBound(xyzpoint, xyzpoint3);
			}
			int num = 0;
			for (int i = 0; i < list.Count; i++)
			{
				if (!list[i].IsAlmostEqualTo(list2[i], 0.0001))
				{
					num = 1;
					break;
				}
			}
			if (num == 0)
			{
				return true;
			}
			num = 0;
			for (int j = 0; j < list.Count; j++)
			{
				if (!list[j].IsAlmostEqualTo(list2[list.Count - j - 1], 0.0001))
				{
					num = 1;
					break;
				}
			}
			return num != 1;
		}

		private void InitDeductionInformationByCurrentDocWall(Dictionary<ElementDataPack, List<ElementDataPack>> dicDeductionWall)
		{
			this.m_dicDeductionWall = new Dictionary<ElementId, List<ElementDataPack>>();
			foreach (KeyValuePair<ElementDataPack, List<ElementDataPack>> keyValuePair in dicDeductionWall)
			{
				foreach (ElementDataPack elementDataPack in keyValuePair.Value)
				{
					if (this.m_dicDeductionWall.ContainsKey(elementDataPack.SelfElementId))
					{
						this.m_dicDeductionWall[elementDataPack.SelfElementId].Add(keyValuePair.Key);
					}
					else
					{
						List<ElementDataPack> list = new List<ElementDataPack>();
						list.Add(keyValuePair.Key);
						this.m_dicDeductionWall.Add(elementDataPack.SelfElementId, list);
					}
				}
			}
		}

		private bool DisallowJoinWall(ElementId BaseWallId)
		{
			Wall wall = this.m_doc.GetElement(BaseWallId) as Wall;
			BoundingBoxXYZ boundingBoxXYZ = wall.get_BoundingBox(null);
			ElementFilter elementFilter = new BoundingBoxIntersectsFilter(new Outline(boundingBoxXYZ.Min, boundingBoxXYZ.Max));
			ElementClassFilter elementClassFilter = new ElementClassFilter(typeof(Wall));
			LogicalAndFilter logicalAndFilter = new LogicalAndFilter(elementFilter, elementClassFilter);
			List<Element> list = new FilteredElementCollector(this.m_doc).WherePasses(logicalAndFilter).WhereElementIsNotElementType().ToElements() as List<Element>;
			ElementArray elementArray = (wall.Location as LocationCurve).get_ElementsAtJoin(0);
			ElementArray elementArray2 = (wall.Location as LocationCurve).get_ElementsAtJoin(1);
			try
			{
				for (int i = 0; i < list.Count; i++)
				{
					Element element = list[i];
					int num = 0;
					num = this.BreakJoinIfTheHeadAndTheTailOrT(wall, element);
					if (num != 1)
					{
						IEnumerator<ElementId> enumerator = JoinGeometryUtils.GetJoinedElements(this.m_doc, element).GetEnumerator();
						{
							while (enumerator.MoveNext())
							{
								if (enumerator.Current == wall.Id)
								{
									JoinGeometryUtils.UnjoinGeometry(this.m_doc, element, wall);
									num = 1;
									break;
								}
							}
						}
					}
				}
				if (WallUtils.IsWallJoinAllowedAtEnd(wall, 0))
				{
					WallUtils.DisallowWallJoinAtEnd(wall, 0);
				}
				if (WallUtils.IsWallJoinAllowedAtEnd(wall, 1))
				{
					WallUtils.DisallowWallJoinAtEnd(wall, 1);
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private int BreakJoinIfTheHeadAndTheTailOrT(Wall wall, Element elem)
		{
			int num = 0;
			IEnumerator enumerator = (elem.Location as LocationCurve).get_ElementsAtJoin(0).GetEnumerator();
			{
				while (enumerator.MoveNext())
				{
					if (((Element)enumerator.Current).Id == wall.Id)
					{
						WallUtils.DisallowWallJoinAtEnd(elem as Wall, 0);
						num = 1;
						break;
					}
				}
			}
			if (num != 1)
			{
				IEnumerator enumerator2 = (elem.Location as LocationCurve).get_ElementsAtJoin(1).GetEnumerator();
				{
					while (enumerator2.MoveNext())
					{
						if (((Element)enumerator2.Current).Id == wall.Id)
						{
							WallUtils.DisallowWallJoinAtEnd(elem as Wall, 1);
							break;
						}
					}
				}
			}
			return num;
		}

		private Dictionary<ElementId, List<ElementDataPack>> m_dicDeductionWall;

		private Document m_doc;

		public int NumEqual;
	}
}
